package com.zhangjingcheng.yunyixia.service.impl;

import com.zhangjingcheng.yunyixia.constant.MessageConstant;
import com.zhangjingcheng.yunyixia.exception.FileBusinessException;
import com.zhangjingcheng.yunyixia.mapper.FileMapper;
import com.zhangjingcheng.yunyixia.pojo.entity.FileInfo;
import com.zhangjingcheng.yunyixia.service.PreviewService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.RandomAccessFile;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;

@Service
@Slf4j
public class PreviewServiceImpl implements PreviewService {

    @Autowired
    private FileMapper fileMapper;

    /**
     * 预览文件
     *
     * @param id
     * @param response
     * @param request
     */
    @Override
    public void preview(Integer id, HttpServletRequest request, HttpServletResponse response) {
        FileInfo fileInfo = fileMapper.selectById(id);
        // 判断文件是否存在
        if (fileInfo == null) {
            throw new FileBusinessException(MessageConstant.FILE_NOT_EXISTS);
        }

        File videoFile = new File(fileInfo.getPath());

        // 检查文件是否存在
        if (!videoFile.exists()) {
            throw new FileBusinessException(MessageConstant.FILE_NOT_EXISTS);
        }

        try {
            // 解析Range请求头
            Long fileSize = fileInfo.getSize();
            String rangeHeader = request.getHeader("Range");
            long start = 0;
            long end = fileSize - 1;
            // 判断是否为分片请求
            boolean isPartial = false;

            if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
                isPartial = true;
                // 解析范围
                String range = rangeHeader.substring(6);
                String[] ranges = range.split("-");
                // 处理分片请求
                if (ranges.length == 2) {
                    if (!ranges[0].isEmpty()) {
                        start = Long.parseLong(ranges[0]);
                    }
                    if (!ranges[1].isEmpty()) {
                        end = Long.parseLong(ranges[1]);
                    }
                } else if (ranges.length == 1) {// 单片请求
                    if (!ranges[0].isEmpty()) {
                        start = Long.parseLong(ranges[0]);
                    }
                }

                // 确保范围有效
                if (start > end || start >= fileSize) {
                    // 在设置响应头之前判断范围有效性
                    response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
                    response.setHeader("Content-Range", "bytes */" + fileSize);
                    return;
                }
                // 若end超过文件大小，则修正为文件末尾
                if (end >= fileSize) {
                    end = fileSize - 1;
                }
            }
            
            // 设置响应头
            String name = fileInfo.getName();
            String suffix = name.substring(name.lastIndexOf(".") + 1).toLowerCase();
            
            // 根据文件扩展名设置正确的Content-Type
            String contentType = getContentType(suffix);
            response.setContentType(contentType);
            
            // 对于文本文件，设置字符编码
            if (suffix.equals("txt") || suffix.equals("html") || suffix.equals("htm") || 
                suffix.equals("css") || suffix.equals("js") || suffix.equals("json") || 
                suffix.equals("xml") || suffix.equals("log") || suffix.equals("md")) {
                response.setCharacterEncoding("UTF-8");
            }
            
            // 告知客户端：服务器支持字节范围请求
            response.setHeader("Accept-Ranges", "bytes");
            response.setHeader("Content-Length", String.valueOf(end - start + 1));

            if (isPartial) {
                // 若为部分请求（有Range头），返回206（表示“部分内容”）
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                // 告知客户端：本次返回的字节范围是[start-end]，文件总大小是fileSize
                response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileSize);
            }

            // 读取并发送文件内容
            try (RandomAccessFile randomAccessFile = new RandomAccessFile(videoFile, "r");
                 FileChannel fileChannel = randomAccessFile.getChannel();
                 WritableByteChannel outputChannel = Channels.newChannel(response.getOutputStream())) {

                // 定位到起始位置并传输指定范围的数据
                fileChannel.transferTo(start, end - start + 1, outputChannel);
            }

        } catch (Exception e) {
            log.error("预览文件失败，文件ID: {}, 错误信息: {}", id, e.getMessage());
            // 如果已经开始输出响应，则不能再抛出异常，只能记录日志
            if (!response.isCommitted()) {
                throw new FileBusinessException(MessageConstant.VIEW_FAILED);
            }
        }
    }
    
    /**
     * 根据文件扩展名获取正确的Content-Type
     * @param suffix 文件扩展名
     * @return Content-Type
     */
    private String getContentType(String suffix) {
        switch (suffix) {
            // 视频文件
            case "mp4":
                return "video/mp4";
            case "avi":
                return "video/avi";
            case "mov":
                return "video/quicktime";
            case "wmv":
                return "video/x-ms-wmv";
            case "flv":
                return "video/x-flv";
            case "webm":
                return "video/webm";
            case "mkv":
                return "video/x-matroska";
            
            // 音频文件
            case "mp3":
                return "audio/mpeg";
            case "wav":
                return "audio/wav";
            case "ogg":
                return "audio/ogg";
            case "aac":
                return "audio/aac";
            case "flac":
                return "audio/flac";
            case "m4a":
                return "audio/mp4";
            
            // 图片文件
            case "jpg":
            case "jpeg":
                return "image/jpeg";
            case "png":
                return "image/png";
            case "gif":
                return "image/gif";
            case "bmp":
                return "image/bmp";
            case "webp":
                return "image/webp";
            case "svg":
                return "image/svg+xml";
            
            // 文档文件
            case "pdf":
                return "application/pdf";
            case "txt":
                return "text/plain; charset=UTF-8";
            case "html":
            case "htm":
                return "text/html; charset=UTF-8";
            case "css":
                return "text/css; charset=UTF-8";
            case "js":
                return "application/javascript; charset=UTF-8";
            case "json":
                return "application/json; charset=UTF-8";
            case "xml":
                return "application/xml; charset=UTF-8";
            case "log":
                return "text/plain; charset=UTF-8";
            case "md":
                return "text/markdown; charset=UTF-8";
            case "csv":
                return "text/csv; charset=UTF-8";
            
            // Office文档文件
            case "doc":
                return "application/msword";
            case "docx":
                return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
            case "xls":
                return "application/vnd.ms-excel";
            case "xlsx":
                return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            case "ppt":
                return "application/vnd.ms-powerpoint";
            case "pptx":
                return "application/vnd.openxmlformats-officedocument.presentationml.presentation";
            
            // 默认类型
            default:
                return "application/octet-stream";
        }
    }
}
